#include "GamePlayState.h"
#include "../SGD Wrappers/SGD_AudioManager.h"
#include "../SGD Wrappers/SGD_GraphicsManager.h"
#include "../SGD Wrappers/SGD_InputManager.h"

#include "../SGD Wrappers/SGD_EventManager.h"
#include "../SGD Wrappers/SGD_Event.h"
#include "../SGD Wrappers/SGD_MessageManager.h"
#include "../SGD Wrappers/SGD_Message.h"

#include "../TinyXML/tinyxml.h"

#include "Game.h"
#include "MainMenuState.h"
#include <sstream>
#include "Entity.h"
#include "EntityManager.h"
#include "Player.h"
#include "Enemy.h"
#include "MessageID.h"
#include "IncreaseHealthMessage.h"
#include "CreateProjectileMessage.h"
#include "DestroyEntityMessage.h"
#include "FireGrappleMessage.h"
#include "Projectiles.h"
#include "ShadowHook.h"
#include "BitmapFont.h"
#include <cstdlib>
#include "ParticleManager.h"
#include "Lightorb.h"
#include "WorldManager.h"
#include "Zone.h"
#include "BossPlanets.h"
#include "Menu.h"
#include "MenuCursor.h"
#include <vector>
#include <fstream>
#include <sstream>
#include <istream>
#include "../TinyXML/tinyxml.h"
#include "Bullet.h"
#include "Disc.h"
#include "Shadowmancer.h"
#include "animation.h"

GamePlayState* GamePlayState::GetInstance(int i)
{
	static GamePlayState instance;
	if (i > -1)
	{
		instance.savefile = i;
	}
	else
		instance.savefile = -1;
	return &instance;
}

void GamePlayState::LoadEmitter(Emitter&load)
{
	SGD::GraphicsManager*graph = SGD::GraphicsManager::GetInstance();
	TiXmlDocument doc;
	doc.LoadFile("resources/xml/AOEbullet.xml");
	TiXmlElement*root = doc.RootElement();
	TiXmlElement*filename = root->FirstChildElement();
	const char* fname = filename->GetText();
	//TiXmlText*name = filename->ToText();
	TiXmlElement*particle = filename->NextSiblingElement();
	string pname = particle->Attribute("Name");
	const char* loop = particle->Attribute("IsLooping");
	const char*burst = particle->Attribute("Bursting");
	TiXmlElement*emitter = particle->FirstChildElement();
	TiXmlElement*shape = emitter->FirstChildElement();
	int s;
	shape->Attribute("shape", &s);
	TiXmlElement*pos = shape->NextSiblingElement();
	string lfname = "resources/images/";
	lfname += fname;
	load.Flyweight.image = graph->LoadTexture(lfname.c_str());
	load.EmitterShape = (EShape)s;
	if (!strcmp(loop, "true"))
		load.looping = true;
	else
		load.looping = false;
	if (!strcmp(burst, "true"))
		load.bursting = true;
	else
		load.bursting = false;
	double help;
	pos->Attribute("x", &help);
	load.Position.x = (float)help;
	pos->Attribute("y", &help);
	load.Position.y = (float)help;
	TiXmlElement*size = pos->NextSiblingElement();
	size->Attribute("width", &help);
	load.Size.width = (float)help;
	size->Attribute("height", &help);
	load.Size.height = (float)help;
	TiXmlElement*num = size->NextSiblingElement();
	num->Attribute("num", &load.NumParticles);
	TiXmlElement*spawn = num->NextSiblingElement();
	spawn->Attribute("rate", &help);
	load.SpawnRate = (float)help;
	TiXmlElement*spread = spawn->NextSiblingElement();
	spread->Attribute("s", &help);
	load.Spread = (float)help;
	TiXmlElement*gravity = spread->NextSiblingElement();
	const char*t = gravity->Attribute("Grav");
	if (!strcmp(t, "true"))
		load.gravity = true;
	else
		load.gravity = false;
	gravity->Attribute("pull", &help);
	load.gravpull = (float)help;
	gravity->Attribute("x", &help);
	load.gravpos.x = (float)help;
	gravity->Attribute("y", &help);
	load.gravpos.y = (float)help;

	TiXmlElement*fly = emitter->NextSiblingElement();
	TiXmlElement*Life = fly->FirstChildElement();
	Life->Attribute("min", &help);
	load.Flyweight.MinLife = (float)help;
	Life->Attribute("max", &help);
	load.Flyweight.MaxLife = (float)help;
	TiXmlElement*Color = Life->NextSiblingElement();
	Color->Attribute("SA", &help);
	load.Flyweight.ColorStartA = (int)help;
	Color->Attribute("SR", &help);
	load.Flyweight.ColorStartR = (int)help;
	Color->Attribute("SG", &help);
	load.Flyweight.ColorStartG = (int)help;
	Color->Attribute("SB", &help);
	load.Flyweight.ColorStartB = (int)help;
	Color->Attribute("EA", &help);
	load.Flyweight.ColorEndA = (int)help;
	Color->Attribute("ER", &help);
	load.Flyweight.ColorEndR = (int)help;
	Color->Attribute("EG", &help);
	load.Flyweight.ColorEndG = (int)help;
	Color->Attribute("EB", &help);
	load.Flyweight.ColorEndB = (int)help;
	TiXmlElement*rot = Color->NextSiblingElement();
	rot->Attribute("start", &help);
	load.Flyweight.RotationStart = (float)help;
	rot->Attribute("change", &help);
	load.Flyweight.RotationChange = (float)help;
	TiXmlElement*scale = rot->NextSiblingElement();
	scale->Attribute("sw", &help);
	load.Flyweight.ScaleStart.width = (float)help;
	scale->Attribute("sh", &help);
	load.Flyweight.ScaleStart.height = (float)help;
	scale->Attribute("cw", &help);
	load.Flyweight.ScaleChange.width = (float)help;
	scale->Attribute("ch", &help);
	load.Flyweight.ScaleChange.height = (float)help;
	TiXmlElement*vel = scale->NextSiblingElement();
	vel->Attribute("sx", &help);
	load.Flyweight.VelocityStart.x = (float)help;
	vel->Attribute("sy", &help);
	load.Flyweight.VelocityStart.y = (float)help;
	vel->Attribute("cx", &help);
	load.Flyweight.VelocityChange.x = (float)help;
	vel->Attribute("cy", &help);
	load.Flyweight.VelocityChange.y = (float)help;
}

void GamePlayState::Enter()
{
	//Initialize the Message Manager
	messages = SGD::MessageManager::GetInstance();
	messages->Initialize(&MessageProc);

	//Store the SGD singletons
	audio = SGD::AudioManager::GetInstance();
	graphics = SGD::GraphicsManager::GetInstance();
	input = SGD::InputManager::GetInstance();

	music = audio->LoadAudio("resources/audio/music.xwm");
	//losemusic = audio->LoadAudio("resources/audio/lose.xwm");
	audio->PlayAudio(music, true);

	bg = graphics->LoadTexture("resources/images/starfield.png");
	arrow = SGD::GraphicsManager::GetInstance()->LoadTexture("resources/images/arrow2.png", { 255, 255, 255, 255 });
	animationArrow = new animation;
	animationArrow->image = SGD::GraphicsManager::GetInstance()->LoadTexture("resources/images/shadow.png");
	animationArrow->initPos = { 0, 0 };
	animationArrow->cellSize = { 32, 32 };
	animationArrow->currCellCol = 0;
	animationArrow->currCellRow = 0;
	animationArrow->timePerFrame = .2f;
	//initialize entity manager
	entities = new EntityManager;

	//Initialize the Particle Manager
	particles = ParticleManager::GetInstance();
	particles->LoadEmitter("resources/xml/Blood2.xml");
	particles->LoadEmitter("resources/xml/AOEbullet.xml");
	particles->LoadEmitter("resources/xml/AOEExplode.xml");
	particles->LoadEmitter("resources/xml/discbullet.xml");
	particles->LoadEmitter("resources/xml/spike2.xml");
	gamefont = new BitmapFont;
	gamefont->Initialize("resources/xml/font1.fnt");

	if (savefile != -1)
	{
		Loadfile();
	}
	else
	{
		world.LoadWorldSeed("resources/xml/worldtooltest.xml");
		player = CreatePlayer();
		entities->AddEntity(player, 2);
		world.PopulateZones();
		//Enemy * newenemy = CreateEnemy();// player, world.GetZones()[0]->GetZoneBoss());
		//newenemy->SetSize({ 32, 32 });
		//newenemy->CalculateRadius();
		//newenemy->SetEType(EType::shaflak);
		//newenemy->SetState(State::track);
		//newenemy->SetRange(100);
		//newenemy->SetCurrentPlanet(world.GetZones()[0]->GetPlanets()[0]);
		//newenemy->SetPosition({ world.GetZones()[0]->GetPlanets()[0]->GetRect().ComputeCenter().x - world.GetZones()[0]->GetPlanets()[0]->GetRadius() - newenemy->GetRadius() / 2,
		//	world.GetZones()[0]->GetPlanets()[0]->GetRect().ComputeCenter().y - world.GetZones()[0]->GetPlanets()[0]->GetRadius() - newenemy->GetRadius() / 2 });
		//entities->AddEntity(newenemy, 1);
		//newenemy->Release();

		PopulateNext();
			
	}
	graphics->SetClearColor({ 0, 0, 0 });
	//init menus
	menu = new Menu;
	menu->Initialize("resources/xml/savemenu.xml");
	std::vector<SGD::Point> p;
	for (unsigned int i = 0; i < menu->menuItems.size(); i++)
		p.push_back(menu->menuItems[i].GetPosition());
	cursor = new MenuCursor;
	cursor->Initialize(p);
	cursor->SetOffset({ -115, 15 });
	cursor->SetSize({ 5, 5 });
	cursor->SetPosition(cursor->GetPositions()[0]);

	saveOptions = new Menu;
	saveOptions->Initialize("resources/xml/savedlg.xml");
	std::vector<SGD::Point> lP;
	for (unsigned int i = 0; i < saveOptions->menuItems.size(); i++)
		lP.push_back(saveOptions->menuItems[i].GetPosition());
	saveCurs = new MenuCursor;
	saveCurs->Initialize(lP);
	saveCurs->SetOffset({ -115, 15 });
	saveCurs->SetSize({ 5, 5 });
	saveCurs->SetPosition(saveCurs->GetPositions()[0]);
	TiXmlDocument doc;
	if (doc.LoadFile("resources/xml/GameSave.xml"))
	{
		TiXmlElement * s1 = doc.RootElement()->FirstChildElement();
		menu->menuItems[0].buttons[0].SetData(s1->Attribute("used"));
		TiXmlElement*s2 = s1->NextSiblingElement();
		menu->menuItems[1].buttons[0].SetData(s2->Attribute("used"));
		TiXmlElement*s3 = s2->NextSiblingElement();
		menu->menuItems[2].buttons[0].SetData(s3->Attribute("used"));
	}
	saveDLG = false;
	paused = false;
	cursPos = 0;
	saveCPos = 0;

	LoadEmitter(ShadowHook::anchorPoint);
	LoadEmitter(ShadowHook::hook);

}


void GamePlayState::Exit()
{
	//particles->FreeAllEmitters();
	particles->UnloadEmitter("Blood");
	particles->UnloadEmitter("AOEBullet");
	particles->UnloadEmitter("AOEExplode");
	particles->UnloadEmitter("discbullet");
	particles->UnloadEmitter("spike");
	particles->FreeAllEmitters();
	particles = nullptr;
	graphics->UnloadTexture(ShadowHook::anchorPoint.Flyweight.image);
	graphics->UnloadTexture(ShadowHook::hook.Flyweight.image);
	graphics->UnloadTexture(animationArrow->image);
	delete animationArrow;
	audio->UnloadAudio(music);
	//audio->UnloadAudio(losemusic);
	graphics->UnloadTexture(bg);
	graphics->UnloadTexture(arrow);
	gamefont->Terminate();
	delete gamefont;
	if (player)
	{
		player->Release();
		player = nullptr;
	}

	if (entities)
	{
		entities->RemoveAll();
		delete entities;
		entities = nullptr;
	}
	// Terminate & deallocate the SGD wrappers
	messages->Terminate();
	messages = nullptr;
	SGD::MessageManager::DeleteInstance();

	delete menu;
	menu = nullptr;
	delete cursor;
	cursor = nullptr;
	delete saveOptions;
	saveOptions = nullptr;
	delete saveCurs;
	saveCurs = nullptr;
	if (zone)
	{
		zone->ReleasePlanets();
		delete zone;
	}

	world.ReleaseZones();
	activeZoneCount = 0;
}

bool GamePlayState::Input()
{
	if (!saveDLG)
	{
		if (input->IsKeyPressed(SGD::Key::Escape) == true)
			if (!player->GetLose())
				paused = !paused;

		if (input->IsKeyPressed(SGD::Key::M))
			mapPause = !mapPause;

		/*TAKE THIS OUT*/
		if (input->IsKeyPressed(SGD::Key::F1))
		{
			SGD::Event e = { "GRAPPLEDETACH" };
			e.SendEventNow(nullptr);
		}
		/*END*/

		if (mapPause)
		{
			if (Game::GetInstance()->GetZoomLevel() != .09f)
				Game::GetInstance()->SetPrevZoomLevel(Game::GetInstance()->GetZoomLevel());
			Game::GetInstance()->SetZoomLevel(.09f);
		}
		else if (!mapPause)
			Game::GetInstance()->SetZoomLevel(Game::GetInstance()->GetPrevZoomLevel());

	}
	if (paused)
	{
		if (input->IsAnyKeyPressed())
			mouseInput = false;
		else if (input->GetMouseMovement() != SGD::Vector{ 0, 0 })
			mouseInput = true;

		if (!saveDLG)
		{
			if (input->IsKeyPressed(SGD::Key::Down) == true
				|| input->IsDPadPressed(0, SGD::DPad::Down))
			{
				SGD::Event e = { "MENUMOVE" };
				e.SendEventNow(nullptr);
				cursPos++;
				if ((unsigned int)cursPos > cursor->GetPositions().size() - 1)
					cursPos = 0;
			}
			if (input->IsKeyPressed(SGD::Key::Up) == true
				|| input->IsDPadPressed(0, SGD::DPad::Up))
			{
				SGD::Event e = { "MENUMOVE" };
				e.SendEventNow(nullptr);
				cursPos--;
				if (cursPos < 0)
					cursPos = cursor->GetPositions().size() - 1;
			}
			if (input->IsKeyPressed(SGD::Key::Enter) == true
				|| input->IsKeyPressed(SGD::Key::LButton) == true
				|| input->IsButtonPressed(0, 0))
			{
				if (cursPos == 0)
				{
					if ("empty" != menu->menuItems[0].buttons[0].GetData())
					{
						toSave = menu->menuItems[0].buttons[0].GetData();
						saveDLG = true;
					}
					else
						Savefile();
				}
				else if (cursPos == 1)
				{
					if ("empty" != menu->menuItems[1].buttons[0].GetData())
					{
						toSave = menu->menuItems[1].buttons[0].GetData();
						saveDLG = true;
					}
					else
						Savefile();
				}
				else if (cursPos == 2)
				{
					if ("empty" != menu->menuItems[2].buttons[0].GetData())
					{
						toSave = menu->menuItems[2].buttons[0].GetData();
						saveDLG = true;
					}
					else
						Savefile();
				}
				else if (cursPos == 3)
				{
					Game::GetInstance()->ChangeState(MainMenuState::GetInstance());
					return true;
				}
			}
		}
		else
		{
			if (input->IsKeyPressed(SGD::Key::Right) == true
				|| input->IsDPadPressed(0, SGD::DPad::Right))
			{
				SGD::Event e = { "MENUMOVE" };
				e.SendEventNow(nullptr);
				saveCPos++;
				if (saveCPos > 2)
					saveCPos = 0;
			}
			else if (input->IsKeyPressed(SGD::Key::Left) == true
				|| input->IsDPadPressed(0, SGD::DPad::Left))
			{
				SGD::Event e = { "MENUMOVE" };
				e.SendEventNow(nullptr);
				saveCPos--;
				if (saveCPos < 0)
					saveCPos = 2;
			}
			if (0 == saveCPos && input->IsKeyPressed(SGD::Key::Enter)
				|| input->IsKeyPressed(SGD::Key::LButton))
			{
				Savefile();
				saveCPos = 0;
				cursPos = 0;
				saveDLG = false;
				paused = false;
			}
			else if (1 == saveCPos && input->IsKeyPressed(SGD::Key::Enter)
				|| input->IsKeyPressed(SGD::Key::LButton))
			{
				Savefile();
				saveCPos = 0;
				saveDLG = false;
			}
			else if (2 == saveCPos && input->IsKeyPressed(SGD::Key::Escape)
				|| input->IsKeyPressed(SGD::Key::LButton))
			{
				saveDLG = false;
				saveCPos = 0;
			}
		}
	}

	return true;
}

void GamePlayState::Update(float elapsedTime)
{
	/*for (int i = 0; i < world.GetZones().size(); i++)
	{
	SGD::Vector temp = player->GetRect().ComputeCenter() - world.GetZones()[i]->GetRect().ComputeCenter();
	float distance = temp.ComputeLength();
	if (distance < player->GetRadius() + world.GetZones()[i]->GetRadius())
	player->SetZoneCounter(i);
	}*/
	if (!world.GetZones()[activeZoneCount - 1]->GetZoneBoss()->GetAlive())
	{
		PopulateNext();
		arrowtimer = 5;
	}
	if (input->IsKeyDown(SGD::Key::Alt))
		arrowtimer = 5;

	arrowactivatetimer += elapsedTime;
	if (arrowactivatetimer > 15)
	{
		arrowtimer = 5;
		arrowactivatetimer = 0;
	}
	if (arrowtimer > 0)
	{
		arrowtimer -= elapsedTime;
		arrowactivatetimer = 0;
	}
	if (!paused && !mapPause)
	{
		entities->UpdateAll(elapsedTime);
		entities->CheckCollisions(0, 1);
		entities->CheckCollisions(0, 2);
		entities->CheckCollisions(0, 3);
		entities->CheckCollisions(1, 2);
		entities->CheckCollisions(1, 3);
		entities->CheckCollisions(2, 2);
		entities->CheckCollisions(2, 3);
		entities->CheckCollisions(3, 3);

		int i = sizeof(player->GetPosition());

		messages->Update();
		particles->UpdateEmitter(elapsedTime);

		//if (player->GetLoseTimer() > 0 && !audio->IsAudioPlaying(losemusic))
		//{
		//	audio->StopAudio(music);
		//	audio->PlayAudio(losemusic);
		//}
		if (player->GetLoseTimer() <= 0)
		{
			Game::GetInstance()->ChangeState(MainMenuState::GetInstance());
			return;
		}
	}
	else if (!mapPause)
	{
		if (!saveDLG)
		{
			if (!mouseInput)
				cursor->SetPosition(cursor->GetPositions()[cursPos]);
			else
			{
				SGD::Rectangle rect{
					input->GetMousePosition(), SGD::Size{ 1, 1 } };
				for (unsigned int i = 0; i < menu->menuItems.size(); i++)
				{
					if (menu->menuItems[i].buttons[0].GetRect().IsIntersecting(rect))
					{
						if (cursPos != i)
						{
							SGD::Event e = { "MENUMOVE" };
							e.SendEventNow(nullptr);
						}
						cursor->SetPosition(cursor->GetPositions()[i]);
						cursPos = i;
					}
				}
			}
			menu->Update(elapsedTime);
		}
		else
		{
			if (!mouseInput)
				saveCurs->SetPosition(saveCurs->GetPositions()[saveCPos]);
			else
			{
				SGD::Rectangle rect{
					input->GetMousePosition(), SGD::Size{ 1, 1 } };
				for (unsigned int i = 0; i < saveOptions->menuItems.size(); i++)
				{
					if (saveOptions->menuItems[i].buttons[0].GetRect().IsIntersecting(rect))
					{
						if (saveCPos != i)
						{
							SGD::Event e = { "MENUMOVE" };
							e.SendEventNow(nullptr);
						}
						saveCurs->SetPosition(saveCurs->GetPositions()[i]);
						saveCPos = i;
					}
				}
			}
			saveOptions->Update(elapsedTime);
		}
	}
	else if (mapPause)
	{
		if (input->IsKeyPressed(SGD::Key::LButton))
			zmPos = input->GetMousePosition();
		if (input->IsKeyDown(SGD::Key::LButton))
			DragMap(elapsedTime);
	}
	animationArrow->timeWaited += elapsedTime;
	if (animationArrow->timeWaited >= animationArrow->timePerFrame)
	{
		animationArrow->timeWaited = 0;
		animationArrow->currCellCol++;
		if (animationArrow->currCellCol > 1)
		{
			animationArrow->currCellCol = 0;
			animationArrow->currCellRow++;
			if (animationArrow->currCellRow > 1)
				animationArrow->currCellRow = 0;
		}
	}
}

void GamePlayState::Render()
{


	if (!paused)
	{
		graphics->DrawTexture(bg, { 0, -15 });
		entities->RenderAll();
		particles->RenderEmitter();
		if (arrowtimer > 0)
		{
			SGD::Vector direction = GetPlayer()->GetRect().ComputeCenter() - world.GetZones()[activeZoneCount - 1]->GetZoneBoss()->GetRect().ComputeCenter();
			direction.Normalize();
			float angle = acosf(direction.y);
			if (direction.x > 0)
				angle = -angle;
			SGD::Point Center{ Game::GetInstance()->GetScreenWidth() / 2 - direction.x * 100, Game::GetInstance()->GetScreenHeight() / 2 - direction.y * 100 };
			graphics->DrawTexture(arrow, Center, angle, { 16, 16 }, { (int)(arrowtimer * 51), 255, 255, 255 });
			//Center = { Game::GetInstance()->GetScreenWidth() / 2 - direction.x * 75, Game::GetInstance()->GetScreenHeight() / 2 - direction.y * 75};
			//animationArrow->Render(Center, angle, arrowtimer);

		}

	}
	else
	{
		if (!saveDLG)
		{
			menu->Render();
			cursor->Render();
		}
		else
		{
			saveOptions->Render();
			saveCurs->Render();
		}
	}
}

void GamePlayState::MessageProc(const SGD::Message* pMsg)
{
#pragma warning( push )
#pragma warning( 1 : 4061 )

	switch (pMsg->GetMessageID())
	{
	case MessageID::MSG_INCREASE_HEALTH:
	{
		GamePlayState::GetInstance()->player->SetHealth(
			GamePlayState::GetInstance()->player->GetHealth() + 1);
	}
		break;
	case MessageID::MSG_CREATE_PROJECTILE:
	{
		const CreateProjectileMessage* proj =
			dynamic_cast<const CreateProjectileMessage*>(pMsg);
		Entity* projectile = GamePlayState::GetInstance()->
			CreateProjectile(dynamic_cast<Enemy*>(proj->GetOwner()), proj->GetData());
		GamePlayState::GetInstance()->entities->AddEntity(projectile, 3);
		projectile->Release();
	}
		break;
	case MessageID::MSG_FIRE_GRAPPLE:
	{
		const FireGrappleMessage* proj =
			dynamic_cast<const FireGrappleMessage*>(pMsg);
		Entity* shadowGrapple = GamePlayState::GetInstance()->
			FireGrapple(proj->GetOwner(), proj->planet);
		GamePlayState::GetInstance()->entities->AddEntity(shadowGrapple, 3);
		shadowGrapple->Release();
	}
		break;
	case MessageID::MSG_DESTROY_ENTITY:
	{
		const DestroyEntityMessage* destMsg =
			dynamic_cast<const DestroyEntityMessage*>(pMsg);
		Entity* ptr = destMsg->GetEntity();
		GamePlayState::GetInstance()->entities->RemoveEntity(ptr);
	}
		break;
	}

#pragma warning( pop )
}

Player* GamePlayState::CreatePlayer()
{
	Player* p = new Player;
	TiXmlDocument doc;
	doc.LoadFile("resources/xml/Player.xml");
	TiXmlElement*root = doc.RootElement();
	TiXmlElement*ats = root->FirstChildElement();
	p->SetHealth((float)atof(ats->Attribute("hp")));
	ats = ats->NextSiblingElement();
	p->SetCorruption((float)atof(ats->Attribute("c")));
	ats = ats->NextSiblingElement();//sprite
	ats = ats->NextSiblingElement();
	p->SetSize({ (float)atof(ats->Attribute("w")), (float)atof(ats->Attribute("h")) });
	if (savefile == -1)
		p->SetPosition(world.GetZones()[0]->GetPosition());
	ats = ats->NextSiblingElement();
	p->SetCurrentState(this);
	return p;
}

Enemy* GamePlayState::CreateEnemy()
{
	std::random_device rd; //create the random device seed
	std::mt19937 mt(rd()); //create the random engine and seed it with the device
	std::uniform_int_distribution<int> randEn(1, 5); //random radius generator for the new planet
	Enemy* e = new Enemy(player);
	TiXmlDocument doc;
	doc.LoadFile("resources/xml/ShaBun.xml");
	TiXmlElement*root = doc.RootElement();
	TiXmlElement*ats = root->FirstChildElement();
	ats = ats->NextSiblingElement();
	e->SetSize({ (float)atof(ats->Attribute("w")), (float)atof(ats->Attribute("h")) });
	e->CalculateRadius();
	e->SetPosition({ 200, 200 });
	ats = ats->NextSiblingElement();
	int x = randEn(mt);
	switch (x)
	{
	case 1:
		e->SetEType(EType::shabun);
		e->SetSize({ 32, 32 });
		break;
	case 2:
		e->SetEType(EType::shadisc);
		break;
	case 3:
		e->SetEType(EType::shaflak);
		break;
	case 4:
		e->SetEType(EType::shike);
		break;
	case 5:
		e->SetEType(EType::shike);
	default:
		break;
	}
	return e;
}

Entity* GamePlayState::CreateProjectile(Enemy* owner, void*data) const
{
	Projectiles* p;
	if (owner->GetEType() == shaflak)
		p = new Bullet("AOEBullet", "AOEExplode");
	else if (owner->GetEType() == shadisc)
		p = new Disc("discbullet");
	else
		p = new Projectiles;
	p->SetSize({ 5, 5 });
	p->CalculateRadius();
	p->SetOwner(owner);
	p->SetPosition(owner->GetRect().ComputeCenter());
	SGD::Vector toTarget;
	if (owner->GetEType() == shike)
		toTarget = owner->GetRect().ComputeCenter() - owner->GetCurrentPlanet()->GetRect().ComputeCenter();
	else if (owner->GetEType() == shadisc)
		toTarget = *((SGD::Point*)data) - owner->GetRect().ComputeCenter();
	else
		toTarget = owner->GetPlayer()->GetRect().ComputeCenter() - p->GetRect().ComputeCenter();
	toTarget.Normalize();
	toTarget *= 200;
	p->SetVelocity(toTarget);
	SGD::Event e = { "ENEMYFIRE" };
	e.SendEventNow(nullptr);
	return p;
}

Planets* GamePlayState::CreatePlanet()
{
	TiXmlDocument doc;
	doc.LoadFile("resources/xml/Planet(template).xml");
	TiXmlElement*root = doc.RootElement();
	TiXmlElement*ats = root->FirstChildElement();
	const char * image = ats->GetText();
	Planets*temp = new Planets();
	string help = "resources/images/";
	help += image;
	temp->SetPosition(player->GetPosition());
	return temp;
}

Entity* GamePlayState::FireGrapple(Entity* owner, Planets*destplanet)
{
	ShadowHook* p = new ShadowHook;
	p->SetSize({ 5, 5 });
	p->CalculateRadius();
	p->SetOwner(owner);
	p->SetPosition(owner->GetPosition());
	if (owner->GetType() == Entity::ENT_PLAYER)
	{
		Player* pl = dynamic_cast<Player*>(owner);
		SGD::Point point;
		SGD::Vector toMouse;
		if (pl->GetControllerGrapple())
		{
			toMouse = pl->GetControllerVector();
			pl->SetControllerGrapple(false);
		}
		else
		{
			point = { input->GetMousePosition().x,
				input->GetMousePosition().y };
			toMouse = point - (SGD::Point{ (owner->GetPosition().x - Game::GetInstance()->GetCameraPos().x) * Game::GetInstance()->GetZoomLevel(),
				(owner->GetPosition().y - Game::GetInstance()->GetCameraPos().y) * Game::GetInstance()->GetZoomLevel() });
		}
		toMouse.Normalize();
		toMouse *= 600;
		p->SetVelocity(toMouse);
		p->SetChains();
	}
	else
	{
		SGD::Point point = { destplanet->GetRect().ComputeCenter().x, destplanet->GetRect().ComputeCenter().y };
		SGD::Vector toPlan = point - owner->GetRect().ComputeCenter();
		toPlan.Normalize();
		toPlan *= 600;
		p->SetVelocity(toPlan);
		p->SetChains();
	}
	return p;
}

Lightorb* GamePlayState::CreateLightorb()
{
	Lightorb* o = new Lightorb();
	o->SetSize({ 16, 16 });
	o->CalculateRadius();
	o->SetPosition({ 200, 200 });
	return o;
}

bool GamePlayState::OutOfBounds(Entity * InvokingObject)
{
	bool outofBounds = true;
	SGD::Vector InZone;
	for (unsigned int x = 0; x < activeZoneCount; x++)
	{
		InZone = InvokingObject->GetRect().ComputeCenter() - world.GetZones()[x]->GetRect().ComputeCenter();
		if (InZone.ComputeLength() > world.GetZones()[x]->GetRadius() * 2)
		{
			for (unsigned int y = 0; y < world.GetZones()[x]->GetAsteroids().size(); y++)
			{
				SGD::Vector Distance = InvokingObject->GetRect().ComputeCenter() - world.GetZones()[x]->GetAsteroids()[y]->GetRect().ComputeCenter();
				if (Distance.ComputeLength() < 500)
				{
					outofBounds = false;
					return outofBounds;
				}
			}
		}
		else return false;
	}



	return outofBounds;
}

bool GamePlayState::WinCheck()
{
	bool win = false;
	for (unsigned int x = 0; x < world.GetZones().size(); x++)
	{
		if (world.GetZones()[x]->GetZoneBoss()->GetAlive())
			return win;
	}
	win = true;
	return win;
}

void GamePlayState::PopulateNext()
{
	if (activeZoneCount < world.GetZones().size())
	{
		entities->AddEntity(world.GetZones()[activeZoneCount]->GetZoneBoss(), 0);
		for (unsigned int j = 0; j < world.GetZones()[activeZoneCount]->GetPlanets().size(); j++)
		{
			entities->AddEntity(world.GetZones()[activeZoneCount]->GetPlanets()[j], 0);
			int chance = rand() % 101;
			if (chance <= world.GetZones()[activeZoneCount]->GetLightChance())
			{
				Lightorb * newlightorb = CreateLightorb();
				int positionangle = rand() % 361;
				newlightorb->SetSize({ 32, 32 });
				SGD::Point position;
				position.x = float(cos(positionangle) * world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetSize().width / 2 + world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetRect().ComputeCenter().x - 16);
				position.y = float(sin(positionangle) * world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetSize().width / 2 + world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetRect().ComputeCenter().y - 16);
				
				newlightorb->SetPosition(position);
				entities->AddEntity(newlightorb, 2);
				newlightorb->Release();
			}
			chance = rand() % 101;
			if (chance <= world.GetZones()[activeZoneCount]->GetEnemyChance())
			{
				Enemy * newenemyobject = CreateEnemy();
				int positionangle = rand() % 361;
				SGD::Point position;
				position.x = float(cos(positionangle) * world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetSize().width / 2 + world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetRect().ComputeCenter().x);
				position.y = float(sin(positionangle) * world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetSize().width / 2 + world.GetZones()[activeZoneCount]->GetPlanets()[j]->GetRect().ComputeCenter().y);
				newenemyobject->SetPosition(position);
				newenemyobject->SetCurrentPlanet(world.GetZones()[activeZoneCount]->GetPlanets()[j]);
				entities->AddEntity(newenemyobject, 1);
				newenemyobject->Release();
			}
		}
		for (unsigned int j = 0; j < world.GetZones()[activeZoneCount]->GetZoneBoss()->GetWeakPoints().size(); j++)
			entities->AddEntity(world.GetZones()[activeZoneCount]->GetZoneBoss()->GetWeakPoints()[j], 1);
		for (unsigned int j = 0; j < world.GetZones()[activeZoneCount]->GetAsteroids().size(); j++)
			entities->AddEntity(world.GetZones()[activeZoneCount]->GetAsteroids()[j], 0);
		activeZoneCount++;
	}
}


void GamePlayState::Loadfile()
{
	TiXmlDocument doc;
	if (doc.LoadFile("resources/xml/GameSave.xml"))
	{
		TiXmlElement*root = doc.RootElement();
		TiXmlElement*load = root->FirstChildElement();
		for (int i = 0; i < savefile; i++)
			load = load->NextSiblingElement();
		TiXmlElement*xplayer = load->FirstChildElement();
		player = CreatePlayer();
		activeZoneCount = atoi(xplayer->Attribute("azone"));
		player->SetHealth((float)atoi(xplayer->Attribute("hp")));
		player->SetCorruption((float)atoi(xplayer->Attribute("c")));
		player->SetSize({ (float)atoi(xplayer->Attribute("w")), (float)atoi(xplayer->Attribute("h")) });
		player->SetPosition({ (float)atoi(xplayer->Attribute("x")), (float)atoi(xplayer->Attribute("y")) });
		player->CalculateRadius();
		player->Setlightorbscollected((int)atoi(xplayer->Attribute("alc")));
		player->Setenemieskilled((int)atoi(xplayer->Attribute("aec")));
		player->Setgrapplesfired((int)atoi(xplayer->Attribute("agc")));
		int x = atoi(xplayer->Attribute("al"));
		if (x)
			player->Setlightorbacheivement(true);
		else
			player->Setlightorbacheivement(false);
		x = atoi(xplayer->Attribute("ae"));
		if (x)
			player->Setenemyacheivement(true);
		else
			player->Setenemyacheivement(false);
		x = atoi(xplayer->Attribute("ag"));
		if (x)
			player->Setgrappleacheivement(true);
		else
			player->Setgrappleacheivement(false);
		entities->AddEntity(player, 2);
		TiXmlElement*xlights = xplayer->NextSiblingElement();
		TiXmlElement*xlight = xlights->FirstChildElement();
		int count;
		xlights->Attribute("count", &count);
		for (int i = 0; i < count; i++)
		{
			if (!xlight)
				break;
			Lightorb* temp = new Lightorb();
			temp->SetPosition({ (float)atof(xlight->Attribute("x")), (float)atof(xlight->Attribute("y")) });
			temp->SetSize({ (float)atof(xlight->Attribute("r")) * 2, (float)atof(xlight->Attribute("r")) * 2 });
			temp->CalculateRadius();
			entities->AddEntity(temp, 2);
			temp->Release();
			xlight = xlight->NextSiblingElement();
		}
		TiXmlElement*xzones = xlights->NextSiblingElement();
		TiXmlElement*xzone = xzones->FirstChildElement();

		xzones->Attribute("count", &count);
		Zone*ztemp = nullptr;
		int planetcount;
		TiXmlElement*xplanet;
		int totalplanets = 0;
		for (int i = 0; i < count; i++)
		{
			if (!xzone)
				break;
			xzone->Attribute("count", &planetcount);
			ztemp = new Zone;
			ztemp->SetPosition({ (float)atof(xzone->Attribute("x")), (float)atof(xzone->Attribute("y")) });
			ztemp->SetRadius((float)atof(xzone->Attribute("r")));
			xplanet = xzone->FirstChildElement();
			totalplanets += planetcount;
			for (int i = 0; i < planetcount; i++)
			{
				if (!xplanet)
					break;
				int x = atoi(xplanet->Attribute("Type"));
				Planets* temp;
				if (x == 6)
				{
					temp = new BossPlanets();
					ztemp->SetZoneBoss((BossPlanets*)temp);
					((BossPlanets*)temp)->SetOwner(ztemp);
					ztemp->GetPlanets().push_back(temp);
				}
				else
				{
					temp = new Planets();
					temp->SetPlanetType((Planets::PlanetType)atoi(xplanet->Attribute("Ptype")));
					switch (temp->GetPlanetType())
					{
					case Planets::PlanetType::ASTD_FOREST:
					case Planets::PlanetType::ASTD_ICE:
					case Planets::PlanetType::ASTD_LAVA:
					case Planets::PlanetType::ASTD_SAND:
					case Planets::PlanetType::ASTD_SHADOW:
						ztemp->AddAsteroid(temp);
						break;
					case Planets::PlanetType::FOREST:
					case Planets::PlanetType::ICE:
					case Planets::PlanetType::LAVA:
					case Planets::PlanetType::SAND:
					case Planets::PlanetType::SHADOW:
						ztemp->GetPlanets().push_back(temp);
						break;
					}
				}
				temp->SetPosition({ (float)atof(xplanet->Attribute("x")), (float)atof(xplanet->Attribute("y")) });
				temp->SetSize({ (float)atof(xplanet->Attribute("r")) * 2, (float)atof(xplanet->Attribute("r")) * 2 });
				temp->CalculateRadius();
				entities->AddEntity(temp, 0);
				xplanet = xplanet->NextSiblingElement();
			}
			world.GetZones().push_back(ztemp);
			xzone = xzone->NextSiblingElement();
		}

		TiXmlElement*xenemies = xzones->NextSiblingElement();
		TiXmlElement*xenemy = xenemies->FirstChildElement();
		int counte;
		xenemies->Attribute("count", &counte);
		for (int i = 0; i < counte; i++)
		{
			if (!xenemy)
				break;
			int x = atoi(xenemy->Attribute("EType"));
			Entity*temp;
			switch (x)
			{
			case 0:
				temp = CreateEnemy();
				((Enemy*)temp)->SetEType(EType::shabun);
				break;
			case 1:
				temp = CreateEnemy();
				((Enemy*)temp)->SetEType(EType::shadisc);
				break;
			case 2:
				temp = CreateEnemy();
				((Enemy*)temp)->SetEType(EType::shaflak);
				break;
			case 3:
				temp = CreateEnemy();
				((Enemy*)temp)->SetEType(EType::shike);
				break;
			case 4:
				temp = CreateEnemy();
				((Enemy*)temp)->SetEType(EType::shatent);
				break;
			case 5:
				temp = new Shadowmancer((Player*)player, (BossPlanets*)entities->Save(0, 0));
				break;
			default:
				temp = new WeakPoint();
				break;
			}
			SGD::Point ppos = { (float)atof(xenemy->Attribute("px")), (float)atof(xenemy->Attribute("py")) };
			Planets*planet;
			for (int i = 0; i < totalplanets; i++)
			{
				planet = ((Planets*)entities->Save(0, i));
				if (ppos == planet->GetPosition())
				{
					if (temp->GetType() == Entity::ENT_WEAKPOINT)
					{
						((WeakPoint*)temp)->SetCurrentPlanet(planet);
						((BossPlanets*)planet)->SetWeakPoint((WeakPoint*)temp);
					}
					else
						((Enemy*)temp)->SetCurrentPlanet(planet);
				
					break;
				}
			}
			temp->SetPosition({ (float)atof(xenemy->Attribute("x")), (float)atof(xenemy->Attribute("y")) });
			temp->SetSize({ (float)atof(xenemy->Attribute("w")), (float)atof(xenemy->Attribute("h")) });
			temp->CalculateRadius();
			entities->AddEntity(temp, 1);
			if (temp->GetType() != Entity::ENT_WEAKPOINT)
				temp->Release();
			xenemy = xenemy->NextSiblingElement();
		}
	}
}

void GamePlayState::Savefile()
{


	/*
		buckets :
		0 = planets
		1 = enemies
		2 = player
		3 = projectiles
		*/
	TiXmlDocument doc;
	if (doc.LoadFile("resources/xml/GameSave.xml"))
	{
		TiXmlElement*root = doc.RootElement();
		TiXmlElement*save = root->FirstChildElement();
		for (int i = 0; i < cursPos; i++)
			save = save->NextSiblingElement();
		if (saveCPos)
		{
			menu->menuItems[cursPos].buttons[0].SetData("empty");
			save->SetAttribute("used", "empty");
			save->RemoveChild(save->FirstChildElement());
			save->RemoveChild(save->FirstChildElement());
			save->RemoveChild(save->FirstChildElement());
			save->RemoveChild(save->FirstChildElement());
			doc.SaveFile();
			return;
		}
		else
		{
			if (!save->NoChildren())
			{
				save->RemoveChild(save->FirstChildElement());
				save->RemoveChild(save->FirstChildElement());
				save->RemoveChild(save->FirstChildElement());
				save->RemoveChild(save->FirstChildElement());
			}
			ostringstream wos;
			wos << "Zones: " << world.GetZones().size();
			save->SetAttribute("used", wos.str().c_str());
			menu->menuItems[cursPos].buttons[0].SetData(wos.str());
			TiXmlElement* xplayer = new TiXmlElement("Player");
			Player*help = (Player*)entities->Save(2, 0);
			SGD::Point pos = help->GetPosition();
			SGD::Size esize = help->GetSize();
			xplayer->SetAttribute("azone", activeZoneCount);
			xplayer->SetAttribute("hp", (int)help->GetHealth());
			xplayer->SetAttribute("c", (int)help->GetCorruption());
			xplayer->SetAttribute("x", (int)pos.x);
			xplayer->SetAttribute("y", (int)pos.y);
			xplayer->SetAttribute("w", (int)esize.width);
			xplayer->SetAttribute("h", (int)esize.height);
			xplayer->SetAttribute("ae", help->Getenemyacheivement());
			xplayer->SetAttribute("al", help->Getlightorbacheivement());
			xplayer->SetAttribute("ag", help->Getgrappleacheivement());
			xplayer->SetAttribute("aec", help->Getenemieskilled());
			xplayer->SetAttribute("alc", help->Getlightorbscollected());
			xplayer->SetAttribute("agc", help->Getgrapplesfired());
			save->LinkEndChild(xplayer);
			TiXmlElement* xlight = new TiXmlElement("LightOrbs");
			size_t size = entities->Size(2) - 1;
			xlight->SetAttribute("count", size);
			TiXmlElement*helper;
			for (size_t i = 0; i < size; i++)
			{
				Entity*help = (Entity*)entities->Save(2, i);
				SGD::Point pos = help->GetPosition();
				if (help->GetType() == Entity::ENT_PLAYER)
					continue;
				helper = new TiXmlElement("LightOrb");
				helper->SetAttribute("x", (int)pos.x);
				helper->SetAttribute("y", (int)pos.y);
				helper->SetAttribute("r", (int)help->GetRadius());
				xlight->LinkEndChild(helper);
			}
			save->LinkEndChild(xlight);
			TiXmlElement* xzones = new TiXmlElement("Zones");
			size = world.GetZones().size();
			xzones->SetAttribute("count", size);
			for (size_t i = 0; i < size; i++)
			{
				TiXmlElement*xzone = new TiXmlElement("Zone");
				xzone->SetAttribute("x", (int)world.GetZones()[i]->GetPosition().x);
				xzone->SetAttribute("y", (int)world.GetZones()[i]->GetPosition().y);
				xzone->SetAttribute("r", (int)world.GetZones()[i]->GetRadius());
				xzone->SetAttribute("count", (int)world.GetZones()[i]->GetPlanets().size() + world.GetZones()[i]->GetAsteroids().size());
				size_t psize = world.GetZones()[i]->GetPlanets().size();// +world.GetZones()[i]->GetAsteroids().size();
				for (size_t j = 0; j < psize; j++)
				{
					helper = new TiXmlElement("Planet");
					Planets*help = world.GetZones()[i]->GetPlanets()[j];
					SGD::Point pos = help->GetPosition();
					helper->SetAttribute("Type", help->GetType());
					helper->SetAttribute("Ptype", help->GetPlanetType());
					helper->SetAttribute("x", (int)pos.x);
					helper->SetAttribute("y", (int)pos.y);
					helper->SetAttribute("r", (int)help->GetRadius());
					xzone->LinkEndChild(helper);
				}
				psize = world.GetZones()[i]->GetAsteroids().size();
				for (size_t j = 0; j < psize; j++)
				{
					helper = new TiXmlElement("Planet");
					Planets*help = world.GetZones()[i]->GetAsteroids()[j];
					SGD::Point pos = help->GetPosition();
					helper->SetAttribute("Type", help->GetType());
					helper->SetAttribute("Ptype", help->GetPlanetType());
					helper->SetAttribute("x", (int)pos.x);
					helper->SetAttribute("y", (int)pos.y);
					helper->SetAttribute("r", (int)help->GetRadius());
					xzone->LinkEndChild(helper);
				}
				xzones->LinkEndChild(xzone);
			}
			save->LinkEndChild(xzones);
			TiXmlElement* xenemies = new TiXmlElement("Enemies");
			size = entities->Size(1);
			xenemies->SetAttribute("count", size);
			for (size_t i = 0; i < size; i++)
			{
				helper = new TiXmlElement("Enemy");
				Enemy*help = (Enemy*)entities->Save(1, i);
				SGD::Point pos = help->GetPosition();
				SGD::Size esize = help->GetSize();
				/*switch (help->GetEType())
				{
				case EType::shabun:
				case EType::shadisc:
				case EType::shaflak:
				case EType::shike:
				case EType::shatent:
				case EType::shamancer:*/
				if (help->GetType() == Entity::ENT_WEAKPOINT)
					helper->SetAttribute("EType", 10);
				else
					helper->SetAttribute("EType", help->GetEType());
				helper->SetAttribute("x", (int)pos.x);
				helper->SetAttribute("y", (int)pos.y);
				helper->SetAttribute("w", (int)esize.width);
				helper->SetAttribute("h", (int)esize.height);
				if (help->GetType() == Entity::ENT_WEAKPOINT)
				{
					helper->SetAttribute("px", (int)((WeakPoint*)help)->GetCurrentPlanet()->GetPosition().x);
					helper->SetAttribute("py", (int)((WeakPoint*)help)->GetCurrentPlanet()->GetPosition().y);
				}
				else
				{
					helper->SetAttribute("px", (int)help->GetCurrentPlanet()->GetPosition().x);
					helper->SetAttribute("py", (int)help->GetCurrentPlanet()->GetPosition().y);
				}
				
				/*	break;
				default:
				break;
				}*/
				xenemies->LinkEndChild(helper);
			}
			save->LinkEndChild(xenemies);

			doc.SaveFile();
		}
	}
}

void GamePlayState::DragMap(float elapsedTime)
{
	SGD::Vector move = zmPos - input->GetInstance()->GetMousePosition();
	SGD::Point camMove = Game::GetInstance()->GetCameraPos();
	camMove += move * 9;
	Game::GetInstance()->SetCameraPos(camMove);
	zmPos = input->GetInstance()->GetMousePosition();
}
